package calao.client.ui;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.ui.PopupListener;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;

public class TooltipProvider 
extends MouseListenerAdapter
implements PopupListener
{
	
	// TODO fix bug that causes tooltip to show when target is no longer visible

	private static final String STYLE = "calao-TooltipPanel";
	private static final int DELAY = 500;
	
	private class TooltipPanel 
	extends PopupPanel 
	{
		final Widget target;
		int left, top;
		public TooltipPanel(Widget target, final Widget content) 
		{
			super(true);
			this.target = target;
			add(content);
			addStyleName(STYLE);
			left = target.getAbsoluteLeft();
			top = target.getAbsoluteTop() + target.getOffsetHeight();
			addPopupListener(TooltipProvider.this);
		}
		public void show()
		{
			setPopupPosition(left, top);
			super.show();
			// make sure the whole panel is visible in main window
			int bottomSpace = Window.getClientHeight()-(top+getOffsetHeight());
			int rightSpace = Window.getClientWidth()-(left+getOffsetWidth());
			if (bottomSpace<0) top = target.getAbsoluteTop() - getOffsetHeight();
			if (rightSpace<0) left += rightSpace;
			if (bottomSpace<0 || rightSpace<0) {
				hide();
				setPopupPosition(left, top);
				super.show();
			}
		}
	}
	
	private boolean running = false;

	private Widget target;
	private TooltipPanel tooltipPanel;
	private Timer timer;	
	
	public TooltipProvider() 
	{
	}

	protected Widget getTooltip(Widget widget)
	{
		return null;
	}

	public void onMouseEnter(Widget sender) 
	{
		targeted(sender);
	}
	
	public void onMouseLeave(Widget sender) 
	{
		target = null;
	}
	
	public void onMouseMove(Widget sender)
	{
		targeted(sender);
	}

	private void targeted(Widget w)
	{
		// handle target change
		if (target!=w) {
			cancelTimer();
			target = w;
		}
		if (running) startTimer();
	}
	
	boolean isParent(Widget a, Widget b)
	{
		if (b==a) return true;
		return b.getParent()!=null? isParent(a, b.getParent()) : false;
	}
		
	private void startTimer()
	{
		if (timer!=null) timer.cancel();
		timer = new Timer() {
			public void run() {
				if (target!=null) {
					if (tooltipPanel!=null) {
						if (tooltipPanel.target==target) return;
						if (isParent(tooltipPanel, target)) return;
						hideTooltip();
					}
					Widget tooltip = getTooltip(target);
					if (tooltip!=null && target.isAttached() && target.isVisible()) {
						tooltipPanel = new TooltipPanel(target, tooltip);
						tooltipPanel.show();
					}
				}
				else {
					hideTooltip();
				}
			}
		};
		timer.schedule(DELAY);		
	}
	
	private void cancelTimer()
	{
		if (timer!=null) timer.cancel();
	}
	
	private void hideTooltip()
	{
		if (tooltipPanel!=null) {
			tooltipPanel.hide();
			tooltipPanel = null;
		}
	}
	
	public void stop()
	{
		running = false;
		cancelTimer();
		hideTooltip();
	}
		
	public void start()
	{
		running = true;
	}

	public void onPopupClosed(PopupPanel sender, boolean autoClosed) 
	{
		if (autoClosed) {
			if (sender==tooltipPanel) tooltipPanel = null;
		}
	}

}
